﻿// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

// Outline shader

// Editable parameters

// Material color
float4 _Color;

// Light color
float4 _LightColor0;

float4 _OutlineColor;
float _OutlineGain;
// Outline thickness
float  _EdgeThickness = 1.0;

// Depth bias to help prevent z-fighting
float  _DepthBias = 12;

float _OutlineSaturate;

float4 _MainTex_ST;


// Main texture
sampler2D _MainTex;

struct a2v
{
	float4 vertex : POSITION;
	float3 normal : NORMAL;
	float4 texcoord : TEXCOORD0;
	float4 color : COLOR;
};
struct v2f
{
	float4 pos : SV_POSITION;
	float2 UV  : TEXCOORD0;
};

// Amount to scale the distance from the camera into a value to scale the outline by. Tweak as desired
#define OUTLINE_DISTANCE_SCALE (20)
// Minimum and maximum outline thicknesses (Before multiplying by _EdgeThickness)
#define OUTLINE_NORMAL_SCALE_MIN (0.005)
#define OUTLINE_NORMAL_SCALE_MAX (0.010)

// Vertex shader
v2f vert(a2v v)
{
	/*
	float4 projPos = UnityObjectToClipPos(v.vertex);
	float4 projNormal = normalize(UnityObjectToClipPos(float4(v.normal, 0)));

	float distanceToCamera = OUTLINE_DISTANCE_SCALE * projPos.z;
	float normalScale = _EdgeThickness * 
		lerp(OUTLINE_NORMAL_SCALE_MIN, OUTLINE_NORMAL_SCALE_MAX, distanceToCamera);
	
	v2f o;
	o.pos = projPos + normalScale * projNormal;
	#ifdef UNITY_REVERSED_Z 
		o.pos.z -= _DepthBias * 0.0001;
	#else
		o.pos.z += _DepthBias * 0.0001;
	#endif	
	*/

	float t = unity_CameraProjection._m11;
	const float Rad2Deg = 180 / UNITY_PI;
	float fov = atan(1.0f / t) * 2.0 * Rad2Deg;

	v2f o;
	float4 pos = float4(UnityObjectToViewPos(v.vertex), 1.0);

	float normalScale = _EdgeThickness *
		lerp(OUTLINE_NORMAL_SCALE_MIN, OUTLINE_NORMAL_SCALE_MAX * (fov/50), abs(pos.z) / OUTLINE_DISTANCE_SCALE) * 0.1;

	float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);

	pos = pos + float4(normalize(normal), 0) * normalScale * v.color.a;

	o.pos = mul(UNITY_MATRIX_P, pos);
#ifdef UNITY_REVERSED_Z 
	o.pos.z -= _DepthBias * 0.0001;
#else
#ifdef UNITY_UV_STARTS_AT_TOP
	o.pos.z += _DepthBias * 0.0001 * abs(_ProjectionParams.z / _ProjectionParams.y);
#else
	o.pos.z += _DepthBias * 0.0001 * abs(_ProjectionParams.z / _ProjectionParams.y + 1);
#endif
#endif	
	o.UV = v.texcoord.xy;
	
	return o;
}

// Get the maximum component of a 3-component color
inline half GetMaxComponent(half3 inColor)
{
	return max(max(inColor.r, inColor.g), inColor.b);
}

// Function to fake setting the saturation of a color. Not a true HSL computation.
inline half3 SetSaturation(half3 inColor, half inSaturation)
{
	// Compute the saturated color to be one where all components smaller than the max are set to 0.
	// Note that this is just an approximation.
	half maxComponent = GetMaxComponent(inColor) - 0.004 * _OutlineSaturate;
	half3 saturatedColor = step(maxComponent.rrr, inColor) * inColor;
	return lerp(inColor, saturatedColor, inSaturation);
}

// Outline color parameters. Tweak as desired
#define SATURATION_FACTOR 0.6
#define BRIGHTNESS_FACTOR 0.8

// Fragment shader
half4 frag(v2f i) : COLOR
{
	half4 mainMapColor = tex2D(_MainTex, i.UV);
	
	half3 outlineColor = BRIGHTNESS_FACTOR
		* SetSaturation(mainMapColor.rgb, SATURATION_FACTOR)
		* mainMapColor.rgb * _OutlineColor.xyz * _OutlineGain;
	
	return half4(outlineColor, 1);
}
